import EventMatcher.matchEvent
import model.EventType
import model.configs.KafkaConfig
import zio.*
import zio.http.*
import zio.config.*
import zio.config.magnolia.deriveConfig
import zio.config.typesafe.*
import zio.json.*
import zio.kafka.*
import zio.kafka.producer.*

object EventWorker extends ZIOAppDefault {
  private val config = ConfigProvider.fromResourcePath().load(deriveConfig[KafkaConfig])

  private val producer =
    ZLayer.fromZIO(
      for {
        kafkaConfig <- TypesafeConfigProvider.fromResourcePath().load(deriveConfig[KafkaConfig])
        _           <- ZIO.logInfo(kafkaConfig.bootstrapServers.mkString)
        producer    <- Producer.make(ProducerSettings(kafkaConfig.bootstrapServers))

      } yield producer
    )

  override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] =
    Runtime.setConfigProvider(ConfigProvider.fromResourcePath())

  private val routes =
    // TODO: разрезать routes на несколько роутов и для каждой группы кидать свои ошибки, не везде идет обработка json
    Routes(
      Method.GET / "ping" -> handler(Response.text("pong")),
      Method.POST / "callback" -> handler { (req: Request) =>
        for {
          body <- req.body.asString.orDie
          // TODO: объединить в один класс? уже есть BaseEventFields?
          extractedType <- ZIO.fromEither(body.fromJson[EventType])
          _             <- ZIO.log(body)
          response      <- matchEvent(extractedType.`type`, body)
        } yield response
      }
    ).handleError { case _: String =>
      Response.badRequest("Wrong JSON payload")
    }

  def run: URIO[Scope & Any, ExitCode] = Server
    .install(routes)
    .flatMap(port => ZIO.logInfo(s"Sever started on http://localhost:$port") *> ZIO.never)
    .provideLayer(producer ++ Server.configured())
    .exitCode
}
